package com.zzhua.processor;

import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;


public class FFmpegProcessor {

    /**
     * 这个方法的url地址都必须是一样的类型 同为post
     */
    public static void convertMediaToM3u8ByHttp(InputStream inputStream, String m3u8Url, String infoUrl, String segmentPattern) throws IOException {

        avutil.av_log_set_level(avutil.AV_LOG_INFO);
        FFmpegLogCallback.set();

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);
        grabber.start();

        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(m3u8Url, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());

        recorder.setFormat("hls");
        recorder.setOption("hls_time", "60");
        recorder.setOption("hls_list_size", "0");
        recorder.setOption("hls_flags", "delete_segments");
        recorder.setOption("hls_delete_threshold", "1");
        recorder.setOption("hls_segment_type", "mpegts");
        /* 这里指定生成的ts文件保存位置，可以写接口路径, 该接口用于接收ts文件流*/
        // recorder.setOption("hls_segment_filename", "http://localhost:8080/upload/test-%d.ts");
        recorder.setOption("hls_segment_filename", segmentPattern);
        recorder.setOption("hls_key_info_file", infoUrl);

        // http属性
        recorder.setOption("method", "POST");

        recorder.setFrameRate(25);
        recorder.setGopSize(2 * 25);
        recorder.setVideoQuality(1.0);
        recorder.setVideoBitrate(10 * 1024);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
        /*
        // 只保存图像，而不保存声音
        recorder.start();
 
        Frame frame;
        while ((frame = grabber.grabImage()) != null) {
            try {
                recorder.record(frame);
            } catch (FrameRecorder.Exception e) {
                e.printStackTrace();
            }
        }
        recorder.setTimestamp(grabber.getTimestamp());
        recorder.close();
        grabber.close();*/

        /* 图像 + 声音 */
        recorder.start(grabber.getFormatContext());
        AVPacket packet;
        while ((packet = grabber.grabPacket()) != null) {
            try {
                recorder.recordPacket(packet);
            } catch (FrameRecorder.Exception e) {
                e.printStackTrace();
            }
        }
        recorder.setTimestamp(grabber.getTimestamp());
        recorder.stop();
        recorder.release();
        grabber.stop();
        grabber.release();
    }

    private static final String BASE_PATH = System.getProperty("user.dir") + "\\tmp\\";


    public static void convertMediaToM3u8(MultipartFile mfile) {

        String origFileName = mfile.getOriginalFilename();
        String fileName = origFileName.substring(0, origFileName.lastIndexOf("."));
        String dirName = fileName;
        String fileDir = BASE_PATH + fileName;
        File dirFile = new File(fileDir);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }

        try {
            File rawFile = new File(dirFile, origFileName);
            // 保存文件
            mfile.transferTo(rawFile);

            // 生成密钥文件
            String commonFileName = fileDir + "\\" + fileName;
            generateKeyFile(commonFileName + ".key");

            // 生成keyInfo文件
            generateKeyInfoFile(dirName, commonFileName + ".key", commonFileName + ".keyinfo");

            convertMediaToM3u8ByHttp(new FileInputStream(rawFile),
                    commonFileName + ".m3u8",
                    commonFileName + ".keyinfo",
                    commonFileName + "-%d.ts");

        } catch (Exception e) {
            e.printStackTrace(System.err);
        }

    }

    /**
     * 生成keyInfo文件
     *
     * @param keyFilePath     密钥文件路径
     * @param keyInfoFilePath keyInfo文件路径
     */
    private static void generateKeyInfoFile(String dirName, String keyFilePath, String keyInfoFilePath) {
        try {
            // 生成IV
            ProcessBuilder ivProcessBuilder = new ProcessBuilder("openssl", "rand", "-hex", "16");
            Process ivProcess = ivProcessBuilder.start();
            BufferedReader ivReader = new BufferedReader(new InputStreamReader(ivProcess.getInputStream()));
            String iv = ivReader.readLine();

            // 写入keyInfo文件
            String keyInfoContent =
                    "http://127.0.0.1:8080/tmp/" + dirName + "/" + new File(keyFilePath).getName() + "\n"
                    + keyFilePath + "\n"
                    + iv;
            Files.write(Paths.get(keyInfoFilePath), keyInfoContent.getBytes());

            System.out.println("keyInfo文件已生成: " + keyInfoFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成密钥文件
     *
     * @param keyFilePath 密钥文件路径
     */
    private static void generateKeyFile(String keyFilePath) {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder("openssl", "rand", "16");
            processBuilder.redirectOutput(new File(keyFilePath));
            Process process = processBuilder.start();
            process.waitFor();
            System.out.println("密钥文件已生成: " + keyFilePath);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}